開始測試前,讓我們在元件中新增一些對外屬性,方便進行測試吧。( ´ ▽ ` )ノ
src\components\wrapper-physics\wrapper-physics.vue
...
<script setup lang="ts">
...
// #region Methods
defineExpose({
...
bodyMap,
bodyInfoMap,
});
// #endregion Methods
</script>
src\components\wrapper-physics\wrapper-physics-body.vue
...
<script setup lang="ts">
...
defineExpose({
id,
info,
});
</script>
新增第一個測試案例吧。
src\components\wrapper-physics\wrapper-physics.spec.ts
import { mount } from '@vue/test-utils';
import { test, expect } from 'vitest';
import WrapperPhysics from './wrapper-physics.vue';
test('沒有任何子元素時 bodyMap 為空', () => {
const wrapper = mount(WrapperPhysics);
expect(wrapper).toBeDefined();
const bodyMap = wrapper.vm.bodyMap;
expect(bodyMap.size).toBe(0);
})
RERUN src/components/wrapper-physics/wrapper-physics.spec.ts x3
✓ src/components/wrapper-physics/wrapper-physics.spec.ts (2)
✓ 沒有任何子元素時 bodyMap 為空
順利通過。
讓我們加入更多註冊物體邏輯吧。◝( •ω• )◟
src\components\wrapper-physics\wrapper-physics.spec.ts
import { mount } from '@vue/test-utils';
import { test, expect } from 'vitest';
import { h } from 'vue';
import WrapperPhysics from './wrapper-physics.vue';
import WrapperPhysicsBody from './wrapper-physics-body.vue';
test('沒有任何子元素時 bodyMap 為空', () => {
const wrapper = mount(WrapperPhysics);
expect(wrapper).toBeDefined();
const bodyMap = wrapper.vm.bodyMap;
expect(bodyMap.size).toBe(0);
})
test('內部僅有非 body 元件子元素時 bodyMap 為空', () => {
const wrapper = mount(WrapperPhysics, {
slots: {
default: '<div>安安</div>',
},
});
expect(wrapper).toBeDefined();
const bodyMap = wrapper.vm.bodyMap;
expect(bodyMap.size).toBe(0);
})
test('bodyMap 數量必須相符 body 元件數量', () => {
const wrapper = mount(WrapperPhysics, {
slots: {
default: [
h(WrapperPhysicsBody),
h(WrapperPhysicsBody),
],
},
});
expect(wrapper).toBeDefined();
const bodyMap = wrapper.vm.bodyMap;
expect(bodyMap.size).toBe(2);
})
最後加入物理模擬相關測試。
src\components\wrapper-physics\wrapper-physics.spec.ts
...
test('start 後物體會移動', async () => {
const wrapper = mount(WrapperPhysics, {
slots: {
default: [
h(WrapperPhysicsBody),
h(WrapperPhysicsBody),
],
},
});
// 等待 bodyInfo 更新
await delay(50);
const bodyInfoMap = wrapper.vm.bodyInfoMap;
bodyInfoMap.forEach((info) => {
expect(info.offsetX).toBe(0);
expect(info.offsetY).toBe(0);
})
wrapper.vm.start();
await delay(500);
bodyInfoMap.forEach((info) => {
expect(info.offsetX).not.toBe(0);
expect(info.offsetY).not.toBe(0);
})
})
test('reset 會清空 bodyInfoMap', async () => {
const wrapper = mount(WrapperPhysics, {
props: {
immediate: true,
},
slots: {
default: [
h(WrapperPhysicsBody),
h(WrapperPhysicsBody),
],
},
});
const bodyInfoMap = wrapper.vm.bodyInfoMap;
await delay(500);
expect(bodyInfoMap.size).toBe(2);
wrapper.vm.reset();
expect(bodyInfoMap.size).toBe(0);
})
test('isStatic 的物體完全不會移動', async () => {
const wrapper = mount(WrapperPhysics, {
props: {
immediate: true,
},
slots: {
default: [
h(WrapperPhysicsBody, { isStatic: true }),
h(WrapperPhysicsBody),
h(WrapperPhysicsBody, { isStatic: true }),
],
},
});
const bodyMap = wrapper.vm.bodyMap;
const bodyInfoMap = wrapper.vm.bodyInfoMap;
await delay(500);
/** 所有靜止物體的 ID */
const staticIds = [...bodyMap.entries()]
.filter(([id, body]) => body.isStatic)
.map(([id]) => id);
[...bodyInfoMap.entries()].forEach(([id, info]) => {
if (staticIds.includes(id)) {
expect(info.offsetX).toBe(0);
expect(info.offsetY).toBe(0);
} else {
expect(info.offsetX).not.toBe(0);
expect(info.offsetY).not.toBe(0);
}
})
})
順利通過!✧*。٩(ˊᗜˋ*)و✧*。
✓ src/components/wrapper-physics/wrapper-physics.spec.ts (6) 1739ms
✓ 沒有任何子元素時 bodyMap 為空
✓ 內部僅有非 body 元件子元素時 bodyMap 為空
✓ bodyMap 數量必須相符 body 元件數量
✓ start 後物體會移動 579ms
✓ reset 會清空 bodyInfoMap 516ms
✓ isStatic 的物體完全不會移動 505ms
Test Files 1 passed (1)
Tests 6 passed (6)
Start at 23:22:48
Duration 2.12s
以上程式碼已同步至 GitLab,大家可以前往下載: